package io.wins.vertx.service.impl;

import io.vertx.core.Future;
import io.vertx.core.Vertx;
import io.vertx.core.eventbus.Message;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.core.logging.Logger;
import io.vertx.core.logging.LoggerFactory;
import io.wins.vertx.entity.Admin;
import io.wins.vertx.entity.Customer;
import io.wins.vertx.entity.User;
import io.wins.vertx.service.BaseService;
import io.wins.vertx.service.UserService;
import io.wins.vertx.utils.EncryptUtils;

public class UserServiceImpl extends BaseService implements UserService {

    private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);

    public UserServiceImpl(final Vertx vertx) {
        this.vertx = vertx;
    }

    @Override
    public UserService listUser(final Message tMessage) {
        final JsonObject sqlMes = new JsonObject()
            .put(SQL, "select * from ds_user");
        this.querySql(sqlMes, this.resultQuery(tMessage, false, null, "Error"));
        return this;
    }

    @Override
    public UserService listUserByPage(final int page, final int limit, final Message tMessage) {
        final JsonObject sqlMes = new JsonObject()
            .put(SQL, "select * from ds_user limit ?, ?")
            .put(PARAMS, new JsonArray().add(this.calcPage(page, limit)).add(limit));
        this.querySql(sqlMes, this.resultQuery(tMessage, false, null, "Error"));
        return this;
    }

    @Override
    public UserService getUserByLoginId(final String loginId, final String password, final int key, final Message tMessage) {
        Future.<JsonObject>future(f -> {
            final JsonObject sqlMes = new JsonObject()
                .put(SQL, "select * from ds_user where login_id = ?")
                .put(PARAMS, new JsonArray().add(loginId));
            this.querySql(sqlMes, r -> {
                if (r.succeeded() && r.result().size() > 0) {
                    final User user = new User(r.result().getJsonObject(0));
                    if (EncryptUtils.verify(password, user.getSalt(), user.getPassword())) {
                        f.complete(user.toJson());
                    } else {
                        logger.warn("Uncorrected user password");
                        tMessage.reply(new JsonObject().put("status", -1));
                        f.fail("Uncorrected user password");
                    }
                } else {
                    logger.error(r.cause());
                    f.fail("User Not Found");
                }
            });
        }).compose(res ->
            Future.<JsonObject>future(f -> {
                User user = new User(res);
                if (key == 1) {
                    this.loadAdminByLoginId(user.getLoginId(), f);
                } else {
                    this.loadCustomerByLoginId(user.getLoginId(), f);
                }
            })
        ).setHandler(asyncResult -> {
            if (asyncResult.failed()) {
                tMessage.fail(500, asyncResult.cause().getMessage());
            } else {
                tMessage.reply(asyncResult.result());
            }
        });
        return this;
    }

    private void loadAdminByLoginId(final String loginId, final Future<JsonObject> f) {
        final JsonObject sqlMes = new JsonObject()
            .put(SQL, "select * from ds_admin where login_id = ?")
            .put(PARAMS, new JsonArray().add(loginId));
        this.querySql(sqlMes, res -> {
            if (res.succeeded() && res.result().size() > 0) {
                final Admin user = new Admin(res.result().getJsonObject(0));
                f.complete(user.toJson());
            } else {
                f.fail("No user");
            }
        });
    }

    private void loadCustomerByLoginId(final String loginId, final Future<JsonObject> f) {
        final JsonObject sqlMes = new JsonObject()
            .put(SQL, "select * from ds_customer where login_id = ?")
            .put(PARAMS, new JsonArray().add(loginId));
        this.querySql(sqlMes, res -> {
            if (res.succeeded() && res.result().size() > 0) {
                final Customer user = new Customer(res.result().getJsonObject(0));
                f.complete(user.toJson());
            } else {
                f.fail("No user");
            }
        });
    }

    @Override
    public UserService registerUser(final User user, final Message tMessage) {
        final JsonObject sqlMes = new JsonObject()
            .put(SQL, "insert into ds_user (id, login_id, password, salt, user_type, last_login) values(?, ?, ?, ?, ?, ?)")
            .put(PARAMS, new JsonArray()
                .add(user.getId())
                .add(user.getLoginId())
                .add(user.getPassword())
                .add(user.getSalt())
                .add(user.getUserType())
                .add(user.getLastLogin()));
        this.insertSql(sqlMes, this.resultUpdate(tMessage, "error happened"));
        return this;
    }

    private void createCustomer(final Customer c) {
        final JsonObject sqlMes = new JsonObject()
            .put(SQL, "insert into ds_customer (id, login_id, nickname, real_name, sex, phone, email, birthday, image, description, created_on, updated_on) values(?,?,?,?,?,?,?,?,?,?,UNIX_TIMESTAMP(),UNIX_TIMESTAMP())")
            .put(PARAMS, new JsonArray()
                .add(c.getId())
                .add(c.getLoginId())
                .add(c.getNickname())
                .add(c.getRealName())
                .add(c.isSex())
                .add(c.getPhone())
                .add(c.getEmail())
                .add(c.getBirthday())
                .add(c.getImage())
                .add(c.getDescription())
            );
        this.insertSql(sqlMes, this.resultNoRespon("error happened"));
    }

    private void createAdministrator(final Admin a) {
        final JsonObject sqlMes = new JsonObject()
            .put(SQL, "insert into ds_admin (id, login_id, role_id, user_name, phone, image, description, created_on, updated_on) values(?,?,?,?,?,?,?,UNIX_TIMESTAMP(),UNIX_TIMESTAMP())")
            .put(PARAMS, new JsonArray()
                .add(a.getId())
                .add(a.getLoginId())
                .add(a.getRoleId())
                .add(a.getUserName())
                .add(a.getPhone())
                .add(a.getImage())
                .add(a.getDescription())
            );
        this.insertSql(sqlMes, this.resultNoRespon("error happened"));
    }

    @Override
    public UserService updateUserPassword(final User user, final Message tMessage) {
        return this;
    }

    @Override
    public UserService checkLoginId(final String loginId, final Message tMessage) {
        final JsonObject sqlMes = new JsonObject()
            .put(SQL, "select 1 from ds_user where login_id = ?")
            .put(PARAMS, new JsonArray().add(loginId));
        this.querySql(sqlMes, res -> {
            if (res.succeeded()) {
                if (res.result().size() > 0) {
                    tMessage.reply(new JsonObject().put("status", -1));
                } else {
                    tMessage.reply(new JsonObject().put("status", 0));
                }
            } else {
                tMessage.reply(new JsonObject().put("status", -1));
            }
        });
        return this;
    }
}
